/***************************************************************************
 *   Copyright (C) 2008 by András Bécsi                                    *
 *   andrewbecsi @ yahoo . co . uk                                         *
 *                                                                         *
 *   This source file is part of the Qtdict project.                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "dictionarypool.h"

//public:

DictionaryPool::DictionaryPool( QObject* parent ):QObject(parent){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    model = new DataModel(this);
    //loadedPlugins = QHash< QByteArray, DictionaryInterface* >();
    loadPlugins();
}

void DictionaryPool::setConnections(){
    qDebug() << "In function "+QString(Q_FUNC_INFO);

    //no errors at first
    errCount=0;

    foreach(DictionaryInterface* dic, pool) {
    // to setup connections properly for newly added dictionaries
    // we need to disconnect first, not to connect twice
        disconnect(dic, SIGNAL(done(DataHash&, const QString&)),
                this, SLOT(finished(DataHash&, const QString& )) );
        disconnect(dic, SIGNAL(errorOccured(const QString &)),
                this, SLOT(handleErrors(const QString&)));

        connect(dic, SIGNAL(done(DataHash&, const QString&)),
                this, SLOT(finished(DataHash&, const QString& )) );
        connect(dic, SIGNAL(errorOccured(const QString &)),
                this, SLOT(handleErrors(const QString&)));
    }
}

void DictionaryPool::collect(const State &state, bool mTrans){
    qDebug() << "In function "+QString(Q_FUNC_INFO);    
    setConnections();
    qDebug("Collecting data...");
    currentWord=state.word;
    data.clear();
    if (!pool.isEmpty()) {

        foreach(DictionaryInterface* dic, pool) {
            if (ONLINE){
                if (!dic->search(state)) {
                    qDebug()<<"Exception: No such database in dictionary!";
                    ++errCount;
                    if (pool.size()==errCount) emit errorOccured( tr("Nem található ilyen szótár!") );
                }
            }else offlineDebug();
        }
    } else {
        qDebug("In function %s: errorOccured signal emitted",Q_FUNC_INFO);
        emit errorOccured( tr("Egy szótár adatbázis sincsen bejelölve!") );
    }
}

const QHash< QByteArray, bool> DictionaryPool::getCurrentSelections(){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    QHash< QByteArray, bool> conf;
    QHashIterator<QByteArray, DictionaryInterface* > iter(loadedPlugins);
    while(iter.hasNext()){
        iter.next();
        conf[ iter.key() ] = iter.value() -> isChecked();
    }
    return conf;
}

bool DictionaryPool::isEnabled(const QByteArray &id){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    return loadedPlugins.value(id)->isChecked();
}


int DictionaryPool::add(DictionaryInterface* dic){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    pool<<dic;
    return pool.size();
}

int DictionaryPool::remove(DictionaryInterface* dic){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    pool.remove(dic);
    return pool.size();
}

void DictionaryPool::clear(){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    pool.clear();
}


void DictionaryPool::sync( bool selection ){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    currentLangs.clear();
    clear();

    foreach(DictionaryInterface* dic, loadedPlugins.values()){
        if (dic->isChecked()){
            add(dic);
            LangHash lhs = dic->getLangHash();
            LangHashIterator iter(lhs);
            while (iter.hasNext()) {
                iter.next();
                currentLangs[iter.key()] = iter.value();
            }
        }
    }

    qDebug()<<"currentLangs.size()="<<currentLangs.size();

    emit refreshRequest( currentLangs );
    qDebug() << "In function "+QString(Q_FUNC_INFO) + " refreshRequest( currentLangs ) emitted ";

    if (selection){
        emit refreshRequest( &loadedPlugins );
        qDebug() << "In function "+QString(Q_FUNC_INFO) + " refreshRequest( getCurrentSelections() ) emitted";
    }

}


const DicHash* DictionaryPool::plugins(){
    return &loadedPlugins;
}

bool DictionaryPool::loadPlugins(){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    loadedPlugins.clear();

    QDir pluginsDir( qApp->applicationDirPath() );
    int errorCnt = -1;

#if defined(Q_OS_WIN)
    if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
        pluginsDir.cdUp();

#elif defined(Q_OS_MAC)
    if (pluginsDir.dirName() == "MacOS") {
        pluginsDir.cdUp();
        pluginsDir.cdUp();
        pluginsDir.cdUp();
    }

#endif
    pluginsDir.cd("plugins");
    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {

        QPluginLoader pluginLoader( pluginsDir.absoluteFilePath(fileName) );
        QObject *plugin = pluginLoader.instance();


        if (plugin) {
            if ( errorCnt == -1 ) ++errorCnt;
            qDebug() << QString(Q_FUNC_INFO)+" qobject_cast<DictionaryInterface *>(plugin)";
            DictionaryInterface* dic = qobject_cast<DictionaryInterface *>(plugin);

            if (dic){
                loadedPlugins.insert(dic->id(), dic);
                qDebug(">>[%s successfully loaded.]<<", qPrintable(pluginsDir.absoluteFilePath(fileName)));
                qDebug()<<">>[  ID = "<< dic->id().toHex() <<"  ]<<";
            } else {
                ++errorCnt;
                qWarning("[WARNING] %s NOT loaded!", qPrintable(pluginsDir.absoluteFilePath(fileName)));
            }
        }else{
            qDebug(">>[!!!Something went wrong. No plugins loaded: %s!!!]<< ", qPrintable( pluginsDir.absoluteFilePath(fileName)) );
        }

        qDebug() << "In function "+QString(Q_FUNC_INFO);
    }


    if ( errorCnt == -1 ){
        emit errorOccured(tr("Nem sikerült szótár-kiegészítőt betölteni!"));

        return false;
        qDebug() << QString(Q_FUNC_INFO)+" return false";
    } else
        if (errorCnt > 0) qDebug(">>[Something went wrong. Some plugins not loaded.]<<");
    else qDebug(">>[%d plugin(s) successfully loaded.]<<", loadedPlugins.size());

    return true;
}

//private slots:
void DictionaryPool::finished(DataHash& hash, const QString& host){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    if ( hash.isEmpty() ) {
        qDebug()<<"Empty hash during request from "<<host;
        ++errCount;
    } else {
        hash.setName(host);
        data << hash;
        qDebug()<<"##! Added data from "<<host;
        qDebug()<<"##! data size = "<<data.size();
    }

    if ( pool.size()-errCount == data.size() ) {
        qDebug()<<"Error Count="<<errCount;
        errCount=0;

        if ( data.isEmpty() ) {
            emit errorOccured( tr("Nincs a jelenlegi beállításoknak megfelelő találat!") );
        } else {
            model->clear();
            model->setData(data);
            qDebug("model.rowCount() = %d", model->rowCount());
            emit tabAdditionRequest( model, currentWord );
        }
    }

}

void DictionaryPool::handleErrors(const QString &msg ){
    emit errorOccured(msg);
}

void DictionaryPool::config( const QHash< QByteArray, bool> &checkHash ){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    QHashIterator<QByteArray, bool> iter(checkHash);
    while(iter.hasNext()){
        iter.next();
        ( loadedPlugins.value(iter.key()) )->setChecked(iter.value());
    }
    sync(false);
}

void DictionaryPool::selectAll(){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    foreach( DictionaryInterface* dic, loadedPlugins.values() ){
        dic->setChecked(true);
    }
    sync();
}

bool DictionaryPool::refreshPlugins(){
    qDebug() << "In function "+QString(Q_FUNC_INFO);
    if( !loadPlugins() ){
        qWarning("[ REFRESH FAILED DUE TO PLUGIN LOADING PROBLEMS ]");
        return false;
    } else sync();
    return true;
}

void DictionaryPool::offlineDebug(){
    DataHash hash;
    hash.add( "szó1", "jelentés1" );
    hash.add( "szó1", "jelentés2" );
    hash.add( "szó1", "jelentés3" );

    hash.add( "szó2", "jelentés1" );
    hash.add( "szó2", "jelentés2" );
    hash.add( "szó2", "jelentés3" );
    hash.add( "szó2", "jelentés4" );
    hash.add( "szó2", "nagyon hosszú jelentés ami ide tartozik" );
    hash.add( "hosszú kefejezés, ami lehet akár egy mondat is", "jelentés1" );
    hash.add( "hosszú kefejezés, ami lehet akár egy mondat is", "jelentés2" );
    hash.add( "hosszú kefejezés, ami lehet akár egy mondat is", "nagyon hosszú jelentés ami ide tartozik" );
    hash.add( "szó3", "jelentés1" );
    hash.add( "szó3", "jelentés2" );
    hash.add( "szó3", "jelentés3" );
    hash.add( "szó3", "jelentés4" );
    hash.add( "szó3", "jelentés5" );

    finished(hash, "Első szótár");
    finished(hash, "Második szótár");
    finished(hash, "Harmadik szótár");
}
